/* 
 * File:    ModAscRtu.h
 * $Author: CreMindES@gmail.com $
 *
 * $Revision: 21 $
 * $Date: 2014-02-16 11:20:40 +0000 (Sun, 16 Feb 2014) $
 */

#ifndef MODASCRTU_H
#define	MODASCRTU_H

// Configuration options

// Enable switching between ASCII-RTU option to both EUSARTs
// #define TRANS_MODE_SELECTION                0


// Device options and ports
//#define _XTAL_FREQ                          16000000
#define _XTAL_FREQ                          40000000

#define USART1_RX_LED_ON()                  LATD0 = 1
#define USART1_RX_LED_OFF()                 LATD0 = 0
#define USART1_TX_LED_ON()                  LATD1 = 1
#define USART1_TX_LED_OFF()                 LATD1 = 0
#define USART2_RX_LED_ON()                  LATD2 = 1
#define USART2_RX_LED_OFF()                 LATD2 = 0
#define USART2_TX_LED_ON()                  LATD3 = 1
#define USART2_TX_LED_OFF()                 LATD3 = 0

#define DISABLE_USART1_RECEPTION()          PIE1bits.RC1IE = 0
#define ENABLE_USART1_RECEPTION()           PIE1bits.RC1IE = 1
#define DISABLE_USART2_RECEPTION()          PIE3bits.RC2IE = 0
#define ENABLE_USART2_RECEPTION()           PIE3bits.RC2IE = 1


// Prototypes

// Device specific functions
void initDevice(void);
void readConfiguration(void);
void initTimer0(void);
void initTimer1(void);
//void initTimer2(void);
void turnLEDsOff(void);
void resetDeviceArray(void);

// Interrupt Routine Service
void interrupt myISR(void);

// USART 1 functions
void initUsart1(void);
void switchUsart1ToTx(void);
void switchUsart1ToRx(void);
void sendUsart1Data(void);

// USART 2 functions
void initUsart2(void);
void switchUsart2ToTx(void);
void switchUsart2ToRx(void);
void sendUsart2Data(void);

// RTU timing functions
void waitForNextRtuCharacter(void);

// Message receiving functions
void receiveAsciiMessage(void);
void receiveRtuMessage(void);
void startReceivingRtuMessage(void);

// Message Validation functions
unsigned char validateAsciiMessage(void);
unsigned char validateRtuMessage(void);

// LRC, CRC validation
unsigned char generateLRC(unsigned char len, unsigned char *buffer);
unsigned int generateCRC(unsigned char len, unsigned char *buffer);

// Converter functions
unsigned char convertAsciiMessageToRtu(void);
unsigned char convertRtuMessageToAscii(void);

unsigned char convertAsciiToRtu(unsigned char *asciiBuffer, unsigned char byteNumber);
unsigned char convertRtuToAscii(unsigned char *rtuBuffer, unsigned char byteNumber);

unsigned char convertHexToAsciiHi(unsigned char num);
unsigned char convertHexToAsciiLo(unsigned char num);

char convertDecToHexInAsciiHi(int num);
char convertDecToHexInAsciiLo(int num);

// Communication stability services
void startTimeoutCheckService(void);        // TODO: finish implementing
void stopTimeoutCheckService(void);
void resetCommunication(void);


// Enumerators
enum communicationStates {
    idle,                       // 0
    receivingAsciiMessage,      // 1
    receivingRtuMessage,        // 2
    convertingDataFormat,       // 3
    sendingMessage,             // 4
    error                       // 5
};

enum messageAvailabilityOptions {
    noMessageIsAvailable,       // 0
    asciiMessageIsAvailable,    // 1
    rtuMessageIsAvailable       // 2
};

enum errosStates {
    noError,                    // 0
    invalidAsciiMessage,        // 1
    invalidRtuMessage,          // 2
    unknownError                // 3
};

enum usartxTransmissionModes {
    ASCII_MODE,                 // 0
    RTU_MODE                    // 1
};

enum txBufferStatusOptions {
    txEmpty,                    // 0
    txAsciiMessageAvailable,    // 1
    txRtuMessageAvailable       // 2
};

enum usartxBaudRateOptions {
    B_2400  = ((unsigned int)_XTAL_FREQ/16/2400)-1,
    B_9600  = ((unsigned int)_XTAL_FREQ/16/9600)-1,
    B_19200 = ((unsigned int)_XTAL_FREQ/16/19200)-1,
    B_38400 = ((unsigned int)_XTAL_FREQ/16/38400)-1
};

enum rtuValidCharTimeoutOptions {
    RtuCharTimeout_baud2400 = 65267,
    RtuCharTimeout_baud9600 = 65468,
    RtuCharTimeout_baud19200 = 65502,
    //RtuCharTimeout_baud38400 = 65518 // baud 40Mhz
    RtuCharTimeout_baud38400 = 237
};


// Variable declarations

static const char hexChars[] = "0123456789ABCDEF";

volatile unsigned char communicationState = 0;
volatile unsigned char messageAvailability = noMessageIsAvailable;
unsigned char txBufferState = txEmpty;
unsigned char errorState = noError;

struct usartxConfiguration{
    unsigned int baudRate;
    unsigned char transmissionMode;
} usart1Configuration, usart2Configuration;

unsigned char usart1BaudRateTemp = 0;
unsigned char usart2BaudRateTemp = 0;

// USART1
unsigned char usart1RxBuffer[150];
unsigned char usart1TxBuffer[150];
unsigned char usart1RxCount = 0;
unsigned char usart1TxCount = 0;

// USART2
unsigned char usart2RxBuffer[150];
unsigned char usart2TxBuffer[150];
unsigned char usart2RxCount = 0;
unsigned char usart2TxCount = 0;

// ASCII Side
unsigned char *asciiRxBuffer =  usart1RxBuffer;
unsigned char *asciiRxCount  = &usart1RxCount;
unsigned char *asciiTxBuffer =  usart1TxBuffer;
unsigned char *asciiTxCount  = &usart1TxCount;

// RTU Side
unsigned char *rtuRxBuffer   =  usart2RxBuffer;
unsigned char *rtuRxCount    = &usart2RxCount;
unsigned char *rtuTxBuffer   =  usart2TxBuffer;
unsigned char *rtuTxCount    = &usart2TxCount;

volatile unsigned char isRtuByteAvailable = 0;
unsigned int rtuValidCharTimeoutOffset = RtuCharTimeout_baud9600;

//unsigned char flush;

unsigned char debug_DummyByte = 0;
unsigned char debug_Usart2RxCount = 0;
unsigned char debug_Usart2RxByte = 0;


#endif	/* MODASCRTU_H */
